#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::analyse() {
    programme();
    cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::programme() {
    // <programme> ::= debut <seqInst> fin <EOF>

    sauterSymCour("debut");
    seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }
    do {
        inst();
        sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "si" || ls.getSymCour() == "tantque" || ls.getSymCour() == "repeter"
            || ls.getSymCour() == "lire" || ls.getSymCour() == "ecrire");

    // tant que le symbole courant est un debut possible d'instruction...
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::inst() {
    // <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>
    if (ls.getSymCour() == "<VARIABLE>") {
        affectation();
    } else if (ls.getSymCour() == "tantque") {
        instTq();
    } else if (ls.getSymCour() == "si") {
        instSi();
    } else if (ls.getSymCour() == "repeter") {
        instRepeter();
    } else if (ls.getSymCour() == "lire") {
        instLire();
    } else if (ls.getSymCour() == "ecrire") {
        instEcrire();
    } else {
        erreur("<inst>");
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::affectation() {
    // <affectation> ::= <variable> = <expression>

    //sauterSymCour("<VARIABLE>");
    testerSymCour("<VARIABLE>");
    ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    expression();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expression() {
    // <expression> ::= <terme> { <opAdd> <terme> }
    terme();

    while ((ls.getSymCour() == "+") || (ls.getSymCour() == "-")) {
        opAdd();
        terme();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::terme() {
    // <terme> ::= <facteur> {<opMult> <facteur>}
    facteur();

    while ((ls.getSymCour() == "*") || (ls.getSymCour() == "/")) {
        opMult();
        facteur();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opAdd() {
    // <opAdd>  ::= + | -
    if ((ls.getSymCour() == "+") || (ls.getSymCour() == "-")) {
        ls.suivant();
    } else {
        erreur("<opAdd>");
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opMult() {
    // <opMult>  ::= * | /
    if ((ls.getSymCour() == "*") || (ls.getSymCour() == "/")) {
        ls.suivant();
    } else {
        erreur("<opMult>");
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::facteur() {
    // <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>" || ls.getSymCour() == "<CHAINE>") {
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
    } else if (ls.getSymCour() == "-") {
        ls.suivant();
        facteur();
    } else if (ls.getSymCour() == "(") {
        ls.suivant();
        expression();
        sauterSymCour(")");
    } else
        erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
        exit(0); // plus tard, on levera une exception
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
            << ls.getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
// Debut 3.3
////////////////////////////////////////////////////////////////////////////////
// Debut 2.2 

void LecteurPhraseAvecTable::expBool() {
    // <expBool> ::= <relation> {<opBool> <relation>}

    relation();
    while (ls.getSymCour() == "et" || ls.getSymCour() == "ou") {
        opBool();
        relation();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opBool() {
    // <opBool> ::= et | ou

    if (ls.getSymCour() == "et" || ls.getSymCour() == "ou") {
        ls.suivant();
    } else {
        erreur("<opBool>");
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::relation() {
    // <relation> ::= <expression> {<opRel> <expression>}

    expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<"
            || ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        opRel();
        expression();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opRel() {
    // <opRel> ::=  == | != | < | <= | > | >=

    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<"
            || ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        ls.suivant();
    } else {
        erreur("<opRel>");
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opUnaire() {
    // <opUnaire> ::= - | non

    if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
        ls.suivant();
    } else {
        erreur("<opBool>");
    }
}
// Fin 2.2
////////////////////////////////////////////////////////////////////////////////
// Debut 2.3

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instSi() {
    // <instSi> ::= si (<expBool>) <seqInst> { sinon (<expBool>) <seqInst> }

    sauterSymCour("si");

    if (ls.getSymCour() == "(") {
        ls.suivant();
        expBool();
        sauterSymCour(")");
    }

    seqInst();

    while (ls.getSymCour() == "sinonsi") {
        ls.suivant();

        if (ls.getSymCour() == "(") {
            ls.suivant();
            expBool();
            sauterSymCour(")");
        }

        seqInst();
    }

    if (ls.getSymCour() == "sinon") {
        ls.suivant();
        seqInst();
    }

    sauterSymCour("finsi");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instTq() {
    // <instTq> ::= tantque (<expBool>) <seqInst> fintantque

    sauterSymCour("tantque");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("fintantque");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instRepeter() {
    // <instRepeter> ::= repeter <seqInst> jusqua (<expBool>)

    sauterSymCour("repeter");
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
}

// Fin 2.3
// Debut 2.4
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instLire() {
    //  <instLire> ::= lire(<variable>) 
    sauterSymCour("lire");
    sauterSymCour("(");
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instEcrire() {
    //  <instEcrire> ::= ecrire (<expression> | <chaine>) 
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>"
            || ls.getSymCour() == "-" || ls.getSymCour() == "non" || ls.getSymCour() == "(") {
        expression();
    } else if (ls.getSymCour() == "CHAINE") {
        ls.suivant();
    }
    sauterSymCour(")");
}
// Fin 2.4
 